import 'dart:async';
import 'dart:math';

import 'package:fijkplayer/fijkplayer.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_video/task/slider.dart';
import 'package:fluttertoast/fluttertoast.dart';

FijkPanelWidgetBuilder fijkPanel3Builder(
    {Key key,
    final bool fill = false,
    final int duration = 5000,
    final bool doubleTap = true,
    final bool snapShot = false,
    final VoidCallback onBack,
    final String title}) {
  return (FijkPlayer player, FijkData data, BuildContext context, Size viewSize,
      Rect texturePos) {
    return _FijkPanel3(
      key: key,
      player: player,
      data: data,
      onBack: onBack,
      viewSize: viewSize,
      texPos: texturePos,
      fill: fill,
      doubleTap: doubleTap,
      snapShot: snapShot,
      hideDuration: duration,
      title: title,
    );
  };
}

/// https://fijkplayer.befovy.com/docs/zh/custom-ui.html#%E6%9C%89%E7%8A%B6%E6%80%81-ui
class _FijkPanel3 extends StatefulWidget {
  final FijkPlayer player;
  final FijkData data;
  final VoidCallback onBack;
  final Size viewSize;
  final Rect texPos;
  final bool fill;
  final bool doubleTap;
  final bool snapShot;
  final int hideDuration;
  final String title;

  const _FijkPanel3(
      {Key key,
      @required this.player,
      this.data,
      this.fill,
      this.onBack,
      this.viewSize,
      this.hideDuration,
      this.doubleTap,
      this.snapShot,
      this.texPos,
      this.title})
      : assert(player != null),
        assert(
            hideDuration != null && hideDuration > 0 && hideDuration < 10000),
        super(key: key);

  @override
  __FijkPanel3State createState() => __FijkPanel3State();
}

class __FijkPanel3State extends State<_FijkPanel3> {
  FijkPlayer get player => widget.player;

  Timer _hideTimer;
  bool _hideStuff = true;

  Timer _statelessTimer;
  bool _prepared = false;
  bool _playing = false;
  FijkState state;

  bool _dragLeft;
  double _volume;
  double _brightness;

  double _seekPos = -1.0;
  double tempNum = 0.0;
  Duration _duration = Duration();
  Duration _currentPos = Duration();
  Duration _bufferPos = Duration();

  StreamSubscription _currentPosSubs;
  StreamSubscription _bufferPosSubs;
  StreamSubscription _isBufferingSubs;
  StreamSubscription _bufferPercentSubs;
  bool isBuffering = false;
  int bufferPercen = 0;

  StreamController<double> _valController;

  // snapshot
  ImageProvider _imageProvider;
  Timer _snapshotTimer;

  //中间进度拖动
  Timer _hhideDragTimer;
  bool _hhideDrag = true;
  double _hdragValue = 0;
  Duration _hdragSeePos = Duration();
  Duration _hdragPos = Duration();

  //加锁
  bool lock = false;
  bool _hideLock = true;

  // Is it needed to clear seek data in FijkData (widget.data)
  bool _needClearSeekData = true;

  static const MyFijkSliderColors sliderColors = MyFijkSliderColors(
      cursorColor: Color.fromARGB(240, 255, 255, 255),
      playedColor: Color.fromARGB(200, 33, 150, 243),
      baselineColor: Color.fromARGB(100, 20, 20, 20),
      bufferedColor: Color.fromARGB(180, 200, 200, 200));

  @override
  void initState() {
    super.initState();

    _valController = StreamController.broadcast();
    _prepared = player.state.index >= FijkState.prepared.index;
    _playing = player.state == FijkState.started;
    _duration = player.value.duration;
    _currentPos = player.currentPos;
    _bufferPos = player.bufferPos;

    _currentPosSubs = player.onCurrentPosUpdate.listen((v) {
      if (_hideStuff == false) {
        setState(() {
          _currentPos = v;
        });
      } else {
        _currentPos = v;
      }
      if (_needClearSeekData) {
        widget.data.clearValue("__fijkview_panel_sekto_position");
      }
      _needClearSeekData = false;
    });

    if (widget.data.contains("__fijkview_panel_sekto_position")) {
      var pos =
          widget.data.getValue("__fijkview_panel_sekto_position") as double;
      _currentPos = Duration(milliseconds: pos.toInt());
    }

    // 当前缓冲位置
    _bufferPosSubs = player.onBufferPosUpdate.listen((v) {
      if (_hideStuff == false) {
        setState(() {
          _bufferPos = v;
        });
      } else {
        _bufferPos = v;
      }
    });
    _isBufferingSubs = player.onBufferStateUpdate.listen((v) {
      if (v) {
        setState(() {
          isBuffering = v;
        });
      } else {
        isBuffering = v;
      }
    });
    _bufferPercentSubs = player.onBufferPercentUpdate.listen((v) {
      if (v > 100) {
        v = 100;
      }
      if (isBuffering) {
        setState(() {
          bufferPercen = v;
        });
      } else {
        bufferPercen = v;
      }
    });
    player.addListener(_playerValueChanged);
  }

  @override
  void dispose() {
    super.dispose();
    _valController?.close();
    _hideTimer?.cancel();
    _statelessTimer?.cancel();
    _snapshotTimer?.cancel();
    _currentPosSubs?.cancel();
    _bufferPosSubs?.cancel();
    _isBufferingSubs?.cancel();
    _bufferPercentSubs?.cancel();
    player.removeListener(_playerValueChanged);
  }

  @override
  Widget build(BuildContext context) {
    Rect rect = panelRect();

    List ws = <Widget>[];

    if (_statelessTimer != null && _statelessTimer.isActive) {
      ws.add(buildStateless());
    } else if (player.state == FijkState.asyncPreparing) {
      ws.add(buildStateless());
    } else if (player.state == FijkState.error) {
      ws.add(buildStateless());
    } else if (_imageProvider != null) {
      ws.add(buildStateless());
    }
    ws.add(buildSeekPos());
    ws.add(buildGestureDetector(context));
    return Positioned.fromRect(
      rect: rect,
      child: Stack(children: ws),
    );
  }

  double dura2double(Duration d) {
    return d != null ? d.inMilliseconds.toDouble() : 0.0;
  }

  void _playerValueChanged() {
    FijkValue value = player.value;

    if (value.duration != _duration) {
      if (_hideStuff == false) {
        setState(() {
          _duration = value.duration;
        });
      } else {
        _duration = value.duration;
      }
    }
    setState(() {
      state = value.state;
    });
    bool playing = (value.state == FijkState.started);
    bool prepared = value.prepared;
    if (playing != _playing ||
        prepared != _prepared ||
        value.state == FijkState.asyncPreparing) {
      setState(() {
        _playing = playing;
        _prepared = prepared;
      });
    }
  }

  void _restartHideTimer() {
    _hideTimer?.cancel();
    _hideTimer = Timer(Duration(milliseconds: widget.hideDuration), () {
      setState(() {
        _hideStuff = true;
        _hideLock = true;
      });
    });
  }

  //退出全屏或返回
  void exitFullScreenOrBack() {
    if (player.value.fullScreen) {
      player.exitFullScreen();
    } else {
      Navigator.pop(context);
    }
  }

  //单击
  void onTapFun() {
    if (_hideStuff == true) {
      _restartHideTimer();
    }
    setState(() {
      if (!lock) {
        _hideStuff = !_hideStuff;
      }
      if (player.value.fullScreen) {
        _hideLock = !_hideLock;
      } else {
        _hideLock = true;
        lock = false;
      }
    });
  }

  //播放或暂停
  void playOrPause() {
    _restartHideTimer();
    if (player.isPlayable() || player.state == FijkState.asyncPreparing) {
      if (player.state == FijkState.started) {
        player.pause();
      } else {
        player.start();
      }
    } else {
      FijkLog.w("Invalid state ${player.state} ,can't perform play or pause");
    }
  }

  //双击
  void onDoubleTapFun() {
    playOrPause();
  }

  //亮度、音量大小
  void onVerticalDragStartFun(DragStartDetails d) {
    if (d.localPosition.dy > panelHeight() - 40) {
      return;
    }
    if (d.localPosition.dx > panelWidth() / 2) {
      // right, volume
      _dragLeft = false;
      FijkVolume.getVol().then((v) {
        if (widget.data != null &&
            !widget.data.contains("__fijkview_panel_init_volume")) {
          widget.data.setValue("__fijkview_panel_init_volume", v);
        }
        setState(() {
          _volume = v;
          _valController.add(v);
        });
      });
    } else {
      // left, brightness
      _dragLeft = true;
      FijkPlugin.screenBrightness().then((v) {
        if (widget.data != null &&
            !widget.data.contains("__fijkview_panel_init_brightness")) {
          widget.data.setValue("__fijkview_panel_init_brightness", v);
        }
        setState(() {
          _brightness = v;
          _valController.add(v);
        });
      });
    }
    _statelessTimer?.cancel();
    _statelessTimer = Timer(const Duration(milliseconds: 2000), () {
      setState(() {});
    });
  }

  void onVerticalDragUpdateFun(DragUpdateDetails d) {
    double delta = d.primaryDelta / panelHeight();
    delta = -delta.clamp(-1.0, 1.0);
    if (_dragLeft != null && _dragLeft == false) {
      if (_volume != null) {
        _volume += delta;
        _volume = _volume.clamp(0.0, 1.0);
        FijkVolume.setVol(_volume);
        setState(() {
          _valController.add(_volume);
        });
      }
    } else if (_dragLeft != null && _dragLeft == true) {
      if (_brightness != null) {
        _brightness += delta;
        _brightness = _brightness.clamp(0.0, 1.0);
        FijkPlugin.setScreenBrightness(_brightness);
        setState(() {
          _valController.add(_brightness);
        });
      }
    }
  }

  void onVerticalDragEndFun(DragEndDetails e) {
    _volume = null;
    _brightness = null;
  }

  //进度滑动
  void onHorizontalDragStartFun(DragStartDetails details) {
    if (_duration != null && _duration.inMilliseconds > 0) {
      _hdragValue = details.localPosition.dx;
      _hdragSeePos = _currentPos;
      setState(() {
        _hhideDrag = false;
      });
    }
  }

  void onHorizontalDragUpdateFun(DragUpdateDetails details) {
    if (_duration != null && _duration.inMilliseconds > 0) {
      double dragValue = dura2double(_hdragSeePos);
      dragValue = dragValue + (details.localPosition.dx - _hdragValue) * 500;
      setState(() {
        _hdragPos = Duration(milliseconds: dragValue.toInt());
      });
    }
  }

  void onHorizontalDragEndFun(DragEndDetails details) {
    if (_duration != null && _duration.inMilliseconds > 0) {
      double see = dura2double(_hdragPos);
      setState(() {
        _seekPos = see;
        player.seekTo(see.toInt());
        _currentPos = Duration(milliseconds: _seekPos.toInt());
        widget.data.setValue("__fijkview_panel_sekto_position", _seekPos);
        _needClearSeekData = true;
        _seekPos = -1.0;
      });
      _hdragValue = 0;
      _hhideDragTimer?.cancel();
      _hhideDragTimer = Timer(Duration(milliseconds: 2000), () {
        setState(() {
          _hhideDrag = true;
        });
      });
    }
  }

  //返回按钮
  Widget buildBack(BuildContext context, double height) {
    bool fullScreen = player.value.fullScreen;
    return IconButton(
      padding: EdgeInsets.all(0),
      iconSize: fullScreen ? height * 0.7 : height * 0.6,
      color: Color(0xFFFFFFFF),
      icon: Icon(Icons.arrow_back_ios_rounded),
      onPressed: exitFullScreenOrBack,
    );
  }

  //视频标题
  Widget buildTitle(BuildContext context, double height) {
    return Text(widget.title,
        style: TextStyle(fontSize: 18, color: Color(0xFFFFFFFF)));
  }

  //播放暂停按钮
  Widget buildPlayButton(BuildContext context, double height) {
    Icon icon = (player.state == FijkState.started)
        ? Icon(Icons.pause_rounded)
        : Icon(Icons.play_arrow_rounded);
    bool fullScreen = player.value.fullScreen;
    return IconButton(
      padding: EdgeInsets.all(0),
      iconSize: fullScreen ? height : height * 0.7,
      color: Color(0xFFFFFFFF),
      icon: icon,
      onPressed: playOrPause,
    );
  }

  //全屏按钮
  Widget buildFullScreenButton(BuildContext context, double height) {
    Icon icon = player.value.fullScreen
        ? Icon(Icons.fullscreen_exit_rounded)
        : Icon(Icons.fullscreen_rounded);
    bool fullScreen = player.value.fullScreen;
    return IconButton(
      padding: EdgeInsets.all(0),
      iconSize: fullScreen ? height : height * 0.7,
      color: Color(0xFFFFFFFF),
      icon: icon,
      onPressed: () {
        player.value.fullScreen
            ? player.exitFullScreen()
            : player.enterFullScreen();
      },
    );
  }

  //播放时间
  Widget buildTimeText(BuildContext context, double height) {
    String text = "${_duration2String(_currentPos)}";
    return Text(text, style: TextStyle(fontSize: 12, color: Color(0xFFFFFFFF)));
  }

  //结束时间
  Widget buildEndTimeText(BuildContext context, double height) {
    String text = "${_duration2String(_duration)}";
    return Text(text, style: TextStyle(fontSize: 12, color: Color(0xFFFFFFFF)));
  }

  //进度条
  Widget buildSlider(BuildContext context) {
    double duration = dura2double(_duration);

    double currentValue = _seekPos >= 0 ? _seekPos : dura2double(_currentPos);
    currentValue = currentValue.clamp(0.0, duration);

    double bufferPos = dura2double(_bufferPos);
    bufferPos = bufferPos.clamp(0.0, duration);

    return MyFijkSlider(
      colors: sliderColors,
      value: currentValue,
      cacheValue: bufferPos,
      min: 0.0,
      max: duration,
      onChanged: (v) {
        _restartHideTimer();
        setState(() {
          _seekPos = v;
        });
      },
      onChangeEnd: (v) {
        setState(() {
          player.seekTo(v.toInt());
          _currentPos = Duration(milliseconds: _seekPos.toInt());
          widget.data.setValue("__fijkview_panel_sekto_position", _seekPos);
          _needClearSeekData = true;
          _seekPos = -1.0;
        });
      },
    );
  }

  //顶部

  Widget buildTop(BuildContext context, double height) {
    return Row(
      children: <Widget>[
        buildBack(context, height),
        buildTitle(context, height),
      ],
    );
  }

  //底部
  Widget buildBottom(BuildContext context, double height) {
    if (_duration != null && _duration.inMilliseconds > 0) {
      return Row(
        children: <Widget>[
          buildPlayButton(context, height),
          buildTimeText(context, height),
          Expanded(child: buildSlider(context)),
          buildEndTimeText(context, height),
          buildFullScreenButton(context, height),
        ],
      );
    } else {
      return Row(
        children: <Widget>[
          buildPlayButton(context, height),
          Expanded(child: Container()),
          buildFullScreenButton(context, height),
        ],
      );
    }
  }

  void takeSnapshot() {
    player.takeSnapShot().then((v) {
      var provider = MemoryImage(v);
      precacheImage(provider, context).then((_) {
        setState(() {
          _imageProvider = provider;
        });
      });
      FijkLog.d("get snapshot succeed");
    }).catchError((e) {
      FijkLog.d("get snapshot failed");
    });
  }

  //构建面板
  Widget buildPanel(BuildContext context) {
    double height = panelHeight();
    bool fullScreen = player.value.fullScreen;
    Widget centerWidget = Container(
      color: Colors.transparent,
      child: GestureDetector(
        onDoubleTap: _hideStuff ? null : onDoubleTapFun,
      ),
    );

    Widget centerChild = Container(
      color: Colors.transparent,
    );

    if (fullScreen) {
      centerWidget = Row(
        children: <Widget>[
          Padding(
            padding: EdgeInsets.only(left: 5, right: 5, top: 5, bottom: 5),
            child: AbsorbPointer(
              absorbing: _hideLock,
              child: AnimatedOpacity(
                opacity: _hideLock ? 0 : 1,
                duration: Duration(microseconds: 10),
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.spaceAround,
                  children: <Widget>[
                    IconButton(
                      padding: EdgeInsets.all(0),
                      color: Color(0xFFFFFFFF),
                      icon: lock
                          ? Icon(Icons.lock_outline_rounded)
                          : Icon(Icons.lock_open_rounded),
                      onPressed: () {
                        setState(() {
                          lock = !lock;
                          if (lock) {
                            _hideStuff = true;
                          } else {
                            _hideStuff = false;
                          }
                          _restartHideTimer();
                        });
                      },
                    ),
                  ],
                ),
              ),
            ),
          ),
          Expanded(child: centerChild),
          Padding(
            padding: EdgeInsets.only(left: 5, right: 5, top: 5, bottom: 5),
            child: AbsorbPointer(
              absorbing: _hideStuff,
              child: AnimatedOpacity(
                opacity: _hideStuff ? 0 : 1,
                duration: Duration(microseconds: 10),
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.spaceAround,
                  children: <Widget>[
                    IconButton(
                      padding: EdgeInsets.all(0),
                      color: Color(0xFFFFFFFF),
                      icon: Icon(Icons.camera_alt),
                      onPressed: () {
                        takeSnapshot();
                      },
                    ),
                  ],
                ),
              ),
            ),
          )
        ],
      );
    }
    return Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: <Widget>[
        AbsorbPointer(
          absorbing: _hideStuff,
          child: AnimatedOpacity(
            opacity: _hideStuff ? 0 : 1,
            duration: Duration(microseconds: 10),
            child: Container(
              height: height > 200 ? 40 : height / 5,
              decoration: BoxDecoration(
                gradient: LinearGradient(
                  colors: [Color(0x88000000), Colors.transparent],
                  begin: Alignment.topCenter,
                  end: Alignment.bottomCenter,
                ),
              ),
              alignment: Alignment.topCenter,
              child: Container(
                height: height > 80 ? 45 : height / 2,
                padding: EdgeInsets.only(left: 5, right: 5, top: 0, bottom: 5),
                child: buildTop(context, height > 80 ? 40 : height / 2),
              ),
            ),
          ),
        ),
        Expanded(
          child: centerWidget,
        ),
        AbsorbPointer(
          absorbing: _hideStuff,
          child: AnimatedOpacity(
            opacity: _hideStuff ? 0 : 1,
            duration: Duration(microseconds: 10),
            child: Container(
              height: height > 200 ? 40 : height / 5,
              decoration: BoxDecoration(
                gradient: LinearGradient(
                  colors: [Color(0x88000000), Color(0x00000000)],
                  end: Alignment.topCenter,
                  begin: Alignment.bottomCenter,
                ),
              ),
              alignment: Alignment.bottomCenter,
              child: Container(
                height: height > 80 ? 45 : height / 2,
                padding: EdgeInsets.only(left: 5, right: 5, top: 0, bottom: 5),
                child: buildBottom(context, height > 80 ? 40 : height / 2),
              ),
            ),
          ),
        )
      ],
    );
  }

  //亮度和音量
  GestureDetector buildGestureDetector(BuildContext context) {
    return GestureDetector(
      onTap: onTapFun,
      onDoubleTap: _hideStuff ? onDoubleTapFun : null,
      onVerticalDragStart: onVerticalDragStartFun,
      onVerticalDragUpdate: onVerticalDragUpdateFun,
      onVerticalDragEnd: onVerticalDragEndFun,
      onHorizontalDragStart: onHorizontalDragStartFun,
      onHorizontalDragUpdate: onHorizontalDragUpdateFun,
      onHorizontalDragEnd: onHorizontalDragEndFun,
      child: buildPanel(context),
    );
  }

  Rect panelRect() {
    Rect rect = player.value.fullScreen || (true == widget.fill)
        ? Rect.fromLTWH(0, 0, widget.viewSize.width, widget.viewSize.height)
        : Rect.fromLTRB(
            max(0.0, widget.texPos.left),
            max(0.0, widget.texPos.top),
            min(widget.viewSize.width, widget.texPos.right),
            min(widget.viewSize.height, widget.texPos.bottom));
    return rect;
  }

  double panelHeight() {
    if (player.value.fullScreen || (true == widget.fill)) {
      return widget.viewSize.height;
    } else {
      return min(widget.viewSize.height, widget.texPos.bottom) -
          max(0.0, widget.texPos.top);
    }
  }

  double panelWidth() {
    if (player.value.fullScreen || (true == widget.fill)) {
      return widget.viewSize.width;
    } else {
      return min(widget.viewSize.width, widget.texPos.right) -
          max(0.0, widget.texPos.left);
    }
  }

  Widget buildStateless() {
    if (_volume != null || _brightness != null) {
      Widget toast = _volume == null
          ? defaultFijkBrightnessToast(_brightness, _valController.stream)
          : defaultFijkVolumeToast(_volume, _valController.stream);
      return IgnorePointer(
        child: AnimatedOpacity(
          opacity: 1,
          duration: Duration(milliseconds: 10),
          child: toast,
        ),
      );
    } else if (player.state == FijkState.asyncPreparing) {
      return Container(
        alignment: Alignment.center,
        child: SizedBox(
          width: 30,
          height: 30,
          child: CircularProgressIndicator(
              valueColor: AlwaysStoppedAnimation(Colors.white)),
        ),
      );
    } else if (player.state == FijkState.error) {
      return Container(
        alignment: Alignment.center,
        child: Icon(
          Icons.error,
          size: 30,
          color: Color(0x99FFFFFF),
        ),
      );
    } else if (_imageProvider != null) {
      _snapshotTimer?.cancel();
      _snapshotTimer = Timer(Duration(milliseconds: 1500), () {
        if (mounted) {
          setState(() {
            _imageProvider = null;
          });
        }
      });
      return Center(
        child: IgnorePointer(
          child: Container(
            decoration: BoxDecoration(
                border: Border.all(color: Colors.yellowAccent, width: 3)),
            child:
                Image(height: 200, fit: BoxFit.contain, image: _imageProvider),
          ),
        ),
      );
    } else {
      return Container();
    }
  }

  //中间进度条
  Widget buildSeekPos() {
    if (!_hhideDrag) {
      return Container(
          alignment: Alignment.center,
          child: Text(
            "${_duration2String(_hdragPos)}/${_duration2String(_duration)}",
            style: TextStyle(
              color: Colors.white,
              fontSize: 22,
            ),
          ));
    } else if (isBuffering) {
      return Align(
        alignment: Alignment(0, -0.4),
        child: Card(
          color: Color.fromRGBO(0, 0, 0, 0.3),
          child: Container(
            padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 8),
            child: Text(
              "$bufferPercen%",
              style: TextStyle(color: Colors.white),
            ),
          ),
        ),
      );
    } else {
      return Container();
    }
  }
}

String _duration2String(Duration duration) {
  if (duration.inMilliseconds < 0) return "-: negtive";

  String twoDigits(int n) {
    if (n >= 10) return "$n";
    return "0$n";
  }

  String twoDigitMinutes = twoDigits(duration.inMinutes.remainder(60));
  String twoDigitSeconds = twoDigits(duration.inSeconds.remainder(60));
  int inHours = duration.inHours;
  return inHours > 0
      ? "$inHours:$twoDigitMinutes:$twoDigitSeconds"
      : "$twoDigitMinutes:$twoDigitSeconds";
}
